--File: NewFile_1.lua
--Author : zhoujibo
--Date   : 2015/5/22
--此文件由[BabeLua]插件自动生成


module('UBBCache',package.seeall)



_POOL_REUSE_STRICT_HIT = 0
_POOL_REUSE_STRICT_MISS = 0
_POOL_REUSE_HIT = 0
_POOL_REUSE_MISS = 0
_POOL_TOTAL = 0

function printInfo()
    local s = '%s: %d(次),%.2f%%'
    print(string.format(s,'严格匹配命中',_POOL_REUSE_STRICT_HIT,(_POOL_REUSE_STRICT_HIT*100)/_POOL_TOTAL))
    print(string.format(s,'严格匹配未命中',_POOL_REUSE_STRICT_MISS,(_POOL_REUSE_STRICT_MISS*100)/_POOL_TOTAL))
    print(string.format(s,'匹配命中',_POOL_REUSE_HIT,(_POOL_REUSE_HIT*100)/_POOL_TOTAL))
    print(string.format(s,'匹配未命中',_POOL_REUSE_MISS,(_POOL_REUSE_MISS*100)/_POOL_TOTAL))
end

--用于存放label对象池 [font|size|color|outlineColor|outline|text]
_LABEL_POOL = {}
--用于存放其他资源的对象池 [scheme][url]
_RES_POOL = {}


--从对象池中查找匹配的对象
--a.从使用池中查找严格匹配的对象 （严格模式）
--b.如果找不到，从全局池中查找严格匹配的对象 （严格模式）
--c.如果找不到，返回空（严格模式），或从使用池中取一对象（非严格模式）
--d.如果找不到，从全局池中取一对象（非严格模式）
--e.如果找不到，生成新对象
--f.将对象从源池中移除，添加到新池中
function getLabelFromPool(key,font,fontSize,color,outlineColor,outlineSize,text,sX,sY,
                        new_pool,label_pool_in_use,strictMode,content_layer)
    _POOL_TOTAL = _POOL_TOTAL+1
    fontSize,_sX,_sY = _getRealFontSizeAndScale(fontSize,sX,sY)
    
    local lb
    key = key or(font..'|'..fontSize..'|'..color..'|'..outlineColor..'|'..outlineSize..'|'..text)
    local fromGlobalPool = false
    if strictMode then
        if label_pool_in_use[key] then
            local oldList = label_pool_in_use[key]
            lb = table.remove(oldList)
            if #oldList==0 then
                label_pool_in_use[key] = nil
            end
        elseif _LABEL_POOL[key] then
            local oldList = _LABEL_POOL[key]
            lb = table.remove(oldList)
            if #oldList==0 then
                _LABEL_POOL[key] = nil
            end
            fromGlobalPool = true
        else
            _POOL_REUSE_STRICT_MISS = _POOL_REUSE_STRICT_MISS+1
            return key,nil
        end
        _POOL_REUSE_STRICT_HIT = _POOL_REUSE_STRICT_HIT+1
    else
        for _key,oldList in pairs(label_pool_in_use)do
            lb = table.remove(oldList)
            if #oldList==0 then
                label_pool_in_use[_key] = nil
            end
            break
        end
        if not lb then
            for _key,oldList in pairs(_LABEL_POOL)do
                lb = table.remove(oldList)
                if #oldList==0 then
                    _LABEL_POOL[_key] = nil
                end
                fromGlobalPool = true
                break
            end
        end
        color = getC4b(color)
        if outlineSize ~= 0 then 
            if outlineColor then
                outlineColor = getC4b(outlineColor)
            else
                outlineColor = cc.c4b(255,255,255,255)
            end
        end
        if lb then
            lb:setTTFConfig({fontFilePath=font,fontSize=fontSize})
            _POOL_REUSE_HIT = _POOL_REUSE_HIT+1
        else
            lb = cc.Label:createWithTTF({fontFilePath=font,fontSize=fontSize},'')
            _POOL_REUSE_MISS = _POOL_REUSE_MISS+1
        end
        lb:setTextColor(color)
        if outlineSize~=0 then
            --加入描边
            lb:enableOutline(outlineColor,outlineSize)
        end
        lb:setString(text)
    end
    if not lb:getParent()then
        content_layer:addChild(lb)
    end
    if fromGlobalPool then
        lb:release()
    end
    if new_pool[key] then
        table.insert(new_pool[key],lb)
    else
        new_pool[key] = {lb}
    end
    lb:setScaleX(_sX)
    lb:setScaleY(_sY)
    return key,lb
end

function getResFromPool(scheme,url,params,sX,sY,new_pool,res_pool_in_use,strictMode,content_layer)
    _POOL_TOTAL = _POOL_TOTAL+1
    local obj
    local fromGlobalPool = false
    local objUrl = url
    if strictMode then
        if res_pool_in_use[scheme] and res_pool_in_use[scheme][url] then
            local oldList = res_pool_in_use[scheme][url]
            obj = table.remove(oldList)
            if #oldList==0 then
                res_pool_in_use[scheme][url] = nil
            end
            _POOL_REUSE_STRICT_HIT = _POOL_REUSE_STRICT_HIT+1
        elseif _RES_POOL[scheme] and _RES_POOL[scheme][url] then
            local oldList = _RES_POOL[scheme][url]
            obj = table.remove(oldList)
            if #oldList==0 then
                _RES_POOL[scheme][url] = nil
            end
            fromGlobalPool = true
            _POOL_REUSE_STRICT_HIT = _POOL_REUSE_STRICT_HIT+1
        else
            _POOL_REUSE_STRICT_MISS = _POOL_REUSE_STRICT_MISS+1
            return nil
        end
    else
        if res_pool_in_use[scheme] then
            for _url,oldList in pairs(res_pool_in_use[scheme])do
                obj = table.remove(oldList)
                objUrl = _url
                if #oldList==0 then
                    res_pool_in_use[scheme][_url] = nil
                end
                _POOL_REUSE_HIT = _POOL_REUSE_HIT+1
                break
            end
        end
        if(not obj)and _RES_POOL[scheme] then
            for _url,oldList in pairs(_RES_POOL[scheme])do
                obj = table.remove(oldList)
                objUrl = _url
                if #oldList==0 then
                    _RES_POOL[scheme][_url] = nil
                end
                _POOL_REUSE_HIT = _POOL_REUSE_HIT+1
                fromGlobalPool = true
                break
            end            
        end
        if not obj then
            _POOL_REUSE_MISS = _POOL_REUSE_MISS+1
        end
    end
    local newobj = UBBStylePlugin.SCHEME_GETOBJ_DICT[scheme](url,params,sX,sY,obj,objKey)
    if not newobj:getParent()then
        content_layer:addChild(newobj)
    end
    if fromGlobalPool then
        --不论老对象是加入了还是没加入，都释放
        obj:release()
    end
    if not new_pool[scheme] then
        new_pool[scheme] = {}
    end
    if new_pool[scheme][url] then
        table.insert(new_pool[scheme][url],newobj)
    else
        new_pool[scheme][url] = {newobj}
    end
    return newobj
end


function moveUnusedObjToPool(label_pool_in_use,res_pool_in_use,content_layer)
    for key,arr in pairs(label_pool_in_use)do
        if _LABEL_POOL[key] then
            arrayConcat(_LABEL_POOL[key],arr)
        else
            _LABEL_POOL[key] = arr
        end
        for i = 1,#arr do
            arr[i]:retain()
            content_layer:removeChild(arr[i])
        end
    end
    for scheme,urlDict in pairs(res_pool_in_use)do
        if not _RES_POOL[scheme] then
            _RES_POOL[scheme] = {}
        end
        for url,arr in pairs(urlDict)do
            if _RES_POOL[scheme][url] then
                arrayConcat(_RES_POOL[scheme][url],arr)
            else
                _RES_POOL[scheme][url] = arr
            end
            for i = 1,#arr do
                arr[i]:retain()
                content_layer:removeChild(arr[i])
            end
        end
    end
end






function _getRealFontSizeAndScale(size,sX,sY)
    if sX>=sY then
        return math.floor(sX*size),1,sY/sX
    else
        return math.floor(sY*size),sX/sY,1
    end
end


_TEST_LABEL = nil --测量用
_SIZE_CACHE = {} --测量结果存储[font][fontSize][char]
function getCharSize(font,fontSize,c,outlineSize,sX,sY)
    local _fontSize,_sX,_sY = _getRealFontSizeAndScale(fontSize,sX,sY)
    if c=='\n' then return 0,_fontSize end --换行符直接返回高度
    if c=='\t' then c = ' ' end  --\t当空格处理
    if #c > 1 then c = '一' end --这里暂时假设中文字体的中文字大小都是一样的，宽度总误差不会超过1
    local cache = _SIZE_CACHE

    if not cache[font] then cache[font] = {} end
    cache = cache[font]
    
    if not cache[_fontSize] then cache[_fontSize] = {} end
    cache = cache[_fontSize]
    
    local _size
    if not cache[c] then
        if not _TEST_LB then
            _TEST_LABEL = cc.Label:create()
            _TEST_LABEL:retain()
        end
        local label = _TEST_LABEL
        label:setTTFConfig({fontFilePath=font,fontSize=_fontSize})
        label:setString(c)
        _size = label:getContentSize()
        cache[c] = _size
    else
        _size = cache[c]
    end
    return(_size.width+outlineSize*2)*_sX,_size.height*_sY
end

--endregion
